package tr.mesir.domain;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.Type;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.annotations.Store;
import org.jboss.envers.Versioned;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

/**
 * With the @Indexed annotation, AddressBook is declared as indexable.  
 * Annotated with @Versioned to make AddressBook versioned.
 * 
 * @author mertcaliskan
 */
@Entity
@Indexed
@Versioned
public class AddressBook extends BaseObject {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7385020761064237507L;

	/*
	 *  @Field determines the fields that will be indexed to be searchable. The index=Index.TOKENIZED will ensure that
	 *  the text will be tokenized using the default Lucene analyzer whereas store=Store.NO ensures that the actual
	 *  data will not be stored in the index.  Index.TOKENIZED and Store.NO are the default values.
	 */
	@Field(index=Index.TOKENIZED, store=Store.NO)
	private String title;
	
	/*
	 * Joda-Time based date is used for the creationDate property and it is persisted by setting the type 
	 * using the hibernate annnotation, @Type.
	 */
	@Column
	@Type(type="org.joda.time.contrib.hibernate.PersistentDateTime")
	private DateTime creationDate = new DateTime();
	
	/*
	 * CascadeType.ALL is added to the contacts property here to get that list be saved while persisting
	 * the addressbook object. Or else hibernate will give org.hibernate.TransientObjectException which
	 * points out to save the transient instance before flushing the AddressBook: tr.mesir.domain.Contact
	 * 
	 * The lifespan of a contact is bounded by the lifespan of AddressBook, so the CascadeType.DELETE_ORPHAN
	 * is used which is supplied by hibernate. 
	 * 
	 * @IndexedEmbedded is added to search a given entity based on the properties of its associated contact objects.
	 */
	@OneToMany(cascade={CascadeType.ALL})
	@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@IndexedEmbedded 
	private List<Contact> contacts = new ArrayList<Contact>();

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public DateTime getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(DateTime creationDate) {
		this.creationDate = creationDate;
	}

	public List<Contact> getContacts() {
		return contacts;
	}

	public void setContacts(List<Contact> contacts) {
		this.contacts = contacts;
	}

	public int getNumOfContacts() {
		return getContacts().size();
	}
	
	public String getCreationDateFormatted() {
		DateTimeFormatter formatter = DateTimeFormat.forPattern("dd-MM-yyyy hh:mm");
		return creationDate.toString(formatter);
	}
	
	@Override
	public String toString() {
		return title + " address book, created on " + getCreationDateFormatted() + " " + " and has " + getNumOfContacts() + " contacts";
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		else if (obj instanceof AddressBook) {
			AddressBook book = (AddressBook) obj;
			return new EqualsBuilder().append(this.title, book.title).isEquals();
		}
		else 
			return false;
	}
}